home *** CD-ROM | disk | FTP | other *** search
- /* This is a very early release of a NIT driver for 4.3 BSD systems.
- * You need to run this program as root. Please think about security
- * during shell escapes, ftp-sessions etc.
- * Define PACKET in config.h to use this driver.
- *
- * SM0RGV
- */
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/param.h>
- #include <sys/stropts.h>
- #include <sys/file.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <net/if.h>
- #include <netinet/in.h>
- #include <netinet/if_ether.h>
- #include <net/nit.h>
- #include <net/nit_if.h>
- #include <net/nit_pf.h>
- #include <net/packetfilt.h>
- #include "global.h"
- #include "config.h"
- #include "enet.h"
- #include "mbuf.h"
- #include "iface.h"
- #include "arp.h"
- #include "netuser.h"
- #include "pktdrvr.h"
- #include "asy.h"
- struct nitdrvr Nitdrvr[NIT_MAX];
- int nit_raw(),nit_stop();
- void nit_input();
-
- extern struct iface *Ifaces;
- extern struct mbuf *Hopper;
- extern char Nospace[];
- int Nnit;
-
- /* Define some TUN stuff to keep the compiler happy */
- struct tundrvr Tundrvr[TUN_MAX];
- int Ntun;
-
- /* Attach a packet driver to the system
- * argv[0]: hardware type, must be "packet"
- * argv[1]: optional ethernet address or 0 for automatic assignment
- * argv[2]: interface label, same as real interface, e.g., "le0"
- * argv[3]: unused
- * argv[4]: maximum transmission unit, bytes, e.g., "8192"
- * argv[5]: optional IP address
- */
- pk_attach(argc,argv,p)
- int argc;
- char **argv;
- void *p;
- {
- struct strioctl si;
- struct ifreq ifr;
- struct timeval timeout;
- struct iface *if_nit;
- struct nitdrvr *pp;
- struct packetfilt filt;
- u_short *fwp;
- int i,if_flags;
- char addr[EADDR_LEN+1], hostn[MAXHOSTNAMELEN];
-
- if(Nnit >= NIT_MAX){
- tprintf("Too many nit drivers\n");
- return -1;
- }
- if(if_lookup(argv[2]) != NULLIF){
- tprintf("Interface %s already exists\n",argv[2]);
- return -1;
- }
- if((if_nit = (struct iface *)calloc(1,sizeof(struct iface))) == NULLIF
- ||(if_nit->name = strdup(argv[2])) == NULLCHAR){
- if(if_nit != NULLIF)
- free((char *)if_nit);
- tprintf(Nospace);
- return -1;
- }
- if_nit->addr = Ip_addr;
- if(argc > 5)
- if_nit->addr = resolve(argv[5]);
- if(if_nit->addr == 0){
- tprintf(Noipaddr);
- free((char *)if_nit);
- return -1;
- }
- pp = &Nitdrvr[Nnit];
- if_nit->mtu = atoi(argv[4]);
- if_nit->dev = Nnit;
- if_nit->raw = nit_raw;
- if_nit->stop = nit_stop;
- pp->iface = if_nit;
- if_nit->send = enet_send;
- if_nit->output = enet_output;
- if_nit->type = CL_ETHERNET;
-
- if((pp->IOser = open("/dev/nit", O_RDWR)) == -1) {
- tprintf("Can't open /dev/nit\n");
- free((char *)if_nit);
- return -1;
- }
-
- /* Arrange to get discrete messages from the stream. */
- ioctl(pp->IOser, I_SRDOPT, (char *)RMSGD);
-
- /* Push the packet filtering module. It will be configured later */
- ioctl(pp->IOser, I_PUSH, "pf");
-
- /* Configure the nit device, binding it to the proper
- underlying interface, and setting nit_if-level flags. */
- strncpy(ifr.ifr_name, argv[2], sizeof ifr.ifr_name);
- si.ic_timout = INFTIM;
-
- si.ic_cmd = NIOCBIND;
- si.ic_len = sizeof ifr;
- si.ic_dp = (char *)𝔦
- i = ioctl(pp->IOser, I_STR, (char *)&si);
- if (i == -1) {
- perror("ioctl bind");
- free((char *)if_nit);
- close (pp->IOser);
- return -1;
- }
- /* Set promiscious mode, ie receive everything */
- if_flags = NI_PROMISC;
- si.ic_cmd = NIOCSFLAGS;
- si.ic_len = sizeof if_flags;
- si.ic_dp = (char *)&if_flags;
- if (ioctl(pp->IOser, I_STR, (char *)&si) == -1) {
- perror("ioctl");
- free((char *)if_nit);
- close(pp->IOser);
- return -1;
- }
-
- /* Get hardware Ethernet address from driver */
- ioctl(pp->IOser,SIOCGIFADDR,&ifr);
-
- if (strcmp(argv[1],"0") == 0) {
- /* Create our own Ethernet address! */
- ifr.ifr_addr.sa_data[0] <<= 1;
-
- /* Check if it is unique */
- i = ether_ntohost(hostn,(struct ether_addr *)ifr.ifr_addr.sa_data);
- if (i && hostn[0] != '\0' && strcmp(hostn,Hostname)){
- tprintf("Bad luck, could not use my Ethernet address.\n");
- free((char *)if_nit);
- close(pp->IOser);
- return -1;
- }
- }
- /* Use the user supplied ethernet address */
- else gether(ifr.ifr_addr.sa_data,argv[1]);
-
- if((if_nit->hwaddr = malloc(EADDR_LEN)) == NULLCHAR){
- free(if_nit->name);
- free((char *)if_nit);
- close(pp->IOser);
- tprintf(Nospace);
- return -1;
- }
- memcpy(if_nit->hwaddr,ifr.ifr_addr.sa_data,EADDR_LEN);
-
- /* Now try to configure the packet filter.
- The filter should eliminate all packets except broadcast
- packets and those directed to us. This is not very easily
- done however. The following will stop most unwanted packets,
- but not all.
- */
- fwp = filt.Pf_Filter;
- for (i=0; i<EADDR_LEN; i += 2) { /* EADDR_LEN == 6 */
- /* Check for own address */
- *fwp++ = ENF_PUSHWORD + i/2;
- *fwp++ = ENF_PUSHLIT | ENF_EQ;
- /* *fwp++ = ENF_PUSHLIT | ENF_CAND;*/
- *fwp++ = *((u_short *) &if_nit->hwaddr[i]);
- /* Check for broadcast address */
- *fwp++ = ENF_PUSHWORD + i/2;
- *fwp++ = ENF_PUSHLIT | ENF_EQ;
- *fwp++ = *((u_short *) &Ether_bdcst[i]);
- *fwp++ = ENF_CNOR;
- }
- filt.Pf_FilterLen = fwp - &filt.Pf_Filter[0];
- i = ioctl(pp->IOser,NIOCSETF,&filt);
- if (i == -1){ perror("ioctl pf"); return -1;}
- /* This didn't filter out all unwanted addresses however! */
-
- /* Flush the read queue, to get rid of anything that accumulated
- before the device reached its final configuration. */
- ioctl(pp->IOser, I_FLUSH, (char *)FLUSHR);
-
- if ((pp->buffer = malloc(pp->iface->mtu)) == NULLCHAR) {
- tprintf("Can't allocate buffer\n");
- free(if_nit->name);
- free((char *)if_nit);
- close(pp->IOser);
- return -1;
- }
- /* Enable interrupt for input to an empty queue */
- ioctl(pp->IOser,I_SETSIG,S_INPUT|S_HIPRI|S_MSG);
- if_nit->next = Ifaces;
- Ifaces = if_nit;
- newproc("ether_rx",2048,nit_input,0,pp,NULL,0);
- pether(addr,if_nit->hwaddr);
- tprintf("Attached %s (%s)\n",ifr.ifr_name,addr);
- ++Nnit;
- return 0;
- }
- /* This is the task that takes care of incoming ethernet packets.
- It would be better to do all this at interrupt level (ie from inpint)
- but the program seems to crash if you do memory allocation operations
- from interrupt level without using alloc.c
- */
- void nit_input(unused,pp,unused2)
- struct nitdrvr *pp;
- void *unused2;
- {
- int res,flags;
- char i_state;
- struct strbuf data, proto;
- struct mbuf *bp;
- struct phdr *phdr;
- fd_set readfds;
- struct timeval timeout;
-
- FD_ZERO (&readfds);
- timeout.tv_sec = 0;
- timeout.tv_usec = 35;
- proto.buf = malloc(ETHERLEN);
- proto.maxlen = ETHERLEN;
- proto.len = 0;
- data.buf = pp->buffer;
- data.maxlen = pp->iface->mtu;
- data.len = 0;
- for (;;) {
- /* If there are no new messages to fetch from the NIT interface,
- * then wait until inpint() gives you a signal.
- */
- i_state = dirps();
- while (FD_SET(pp->IOser,&readfds), select(NOFILE,
- &readfds,(fd_set *)0,(fd_set *)0,&timeout) <= 0)
- pwait(pp);
- restore(i_state);
- flags = 0;
- res = getmsg(pp->IOser,&proto,&data,&flags);
- if (res == -1)
- perror("getmsg");
-
- /* Process the packet.
- /* Since I didn't manage to make the filter inhibit all unwanted
- packets we must check the destination address one more time */
- if (memcmp(pp->iface->hwaddr,data.buf,EADDR_LEN)
- && memcmp(Ether_bdcst,data.buf,EADDR_LEN))
- continue;
-
- if((bp = alloc_mbuf(data.len+sizeof(struct phdr))) == NULLBUF){
- tprintf(Nospace);
- continue;
- }
- memcpy(bp->data+sizeof(struct phdr),data.buf,data.len);
- /* Generate descriptor header */
- phdr = (struct phdr *)bp->data;
- phdr->iface = pp->iface;
- phdr->type = CL_ETHERNET;
- bp->cnt = data.len + sizeof(struct phdr);
- if (res & MOREDATA)
- tprintf("Problems, packet truncated!\n");
- enqueue(&Hopper,bp);
- }
- }
- /* Send raw packet (caller provides header) */
- int
- nit_raw(iface,bp)
- struct iface *iface; /* Pointer to interface control block */
- struct mbuf *bp; /* Data field */
- {
- register struct nitdrvr *pp;
- struct mbuf *bp1;
- struct strbuf proto,data;
- struct sockaddr sock;
- short size;
-
- pp = &Nitdrvr[iface->dev];
-
- /* pp->stats.xmit++;*/
-
- size = len_p(bp);
-
- if(size < RUNT)
- size = RUNT;
- if(bp->next != NULLBUF){
- /* Copy to contiguous buffer, since driver can't handle mbufs */
- bp1 = copy_p(bp,size);
- free_p(bp);
- bp = bp1;
- if(bp == NULLBUF)
- return -1;
- } else
- bp->cnt = size; /* Make sure packet size is big enough */
-
- dump(iface,IF_TRACE_OUT,CL_ETHERNET,bp);
-
- /* Now send the packet to the NIT interface */
- sock.sa_family = AF_UNSPEC;
- memcpy(sock.sa_data,bp->data,ETHERLEN);
- proto.buf = (char *) &sock;
- proto.len = sizeof (struct sockaddr);
- data.buf = bp->data+ETHERLEN;
- data.len = bp->cnt-ETHERLEN;
- if (putmsg(pp->IOser,&proto,&data,0) == -1)
- perror("putmsg");
- free_p(bp);
- return 0;
- }
-
- int nit_stop()
- {}
-